#include <iostream>
#include <functional>
#include <string>
#include <unordered_map>
#include "Sock.hpp"
#include "Epoll.hpp"
#include<functional>
using namespace std;
class TcpServer;
class Connection;
using func_t = std::function<void(Connection *)>;

class Connection    
{
public:
    Connection(TcpServer* tp,func_t recv,func_t send,func_t except,int sock)
    :_tp(tp)
    ,_send(send)
    ,_recv(recv)
    ,_except(except)
    ,_sock(sock)
    {}
    ~Connection()
    {}
public:     //暂时将回调方法暴露出来
    func_t _send;
    func_t _recv;
    func_t _except;
    TcpServer* _tp;
    string inbuffer;     //数据接收缓冲区
    string outbuffer;    //数据发送缓冲区
    int _sock;
};

class TcpServer
{
public:
    TcpServer(int port,int revs_num)
    :_port(port)
    ,_revs_num(revs_num)
    {
        _listensock=Sock::Socket();
        Sock::Bind(_listensock,_port);
        Sock::Listen(_listensock);
        _poll.CreateEpoll();
        AddConnection(_listensock,bind(&TcpServer::Accepter,this,placeholders::_1),nullptr,nullptr);
        _revs=new epoll_event[revs_num]; 
        
    }
    void AddConnection(int sock,func_t recv,func_t send,func_t except)
    {
        Sock::SetNonBlock(sock);       //设置事件为非阻塞
        Connection* con=new Connection(this,recv,send,except,sock);
        con->_tp=this;
        //添加到epoll中建立联系
        _poll.AddSockToEpoll(sock,EPOLLIN | EPOLLET);   //设置添加的默认事件(默认加入读和ET模式)
        //添加到哈希表中
        _connections.insert(make_pair(sock,con));
        cout<<"链接成功"<<endl;
    }
    void Accepter(Connection* con)
    {
        while(1)
        {
            string clientip;
            uint16_t clientport;
              int accept_errno = 0;   //用于处理错误信息
            int sock=Sock::Accept(_listensock);  //Accept的返回值就是对应链接的套接字sock
            if(sock>=0) //连接成功的情况
            {
                AddConnection(sock, std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
            }
            else   //错误原因分类
            {
                if (accept_errno == EAGAIN || accept_errno == EWOULDBLOCK)
                    break;
                else if (accept_errno == EINTR) //链接中断
                    continue; // 概率非常低
                else    //accpet链接失败
                {
                    break;
                }
            }

        }
    }
    void LoopOnce()   //处理就绪事件
    {
        int n=_poll.WaitEpoll(_revs,_revs_num); 
        for(int i=0;i<n;i++)
        {
            int sock=_revs[i].data.fd;     
            uint32_t revents=_revs[i].events;
            //将所有的异常统一交给read或write处理
            if(revents&EPOLLIN)
            {
                if(IsConnectionExists(sock)&&_connections[sock]->_recv)//确保套接字存在并且回调方法存在
                _connections[sock]->_recv(_connections[sock]);
            }
            if(revents&EPOLLOUT)
            {
                if(IsConnectionExists(sock)&&_connections[sock]->_send)
                _connections[sock]->_send(_connections[sock]);
            }
        }
    }
    void run()      //运行
    {
        while(1)
        {
            LoopOnce();
        }
    }
    ~TcpServer()
    {
        for(auto&iter:_connections)
        {
            int sock=iter.first;
            Connection* con=iter.second;
            close(sock);   //关闭套接字
            delete con;     //关闭链接
        }
        if(_revs)
        delete []_revs;     //清空就绪队列
    }
    bool IsConnectionExists(int sock)   //检测套接字是否存在
    {
        if(!_connections.count(sock))
        return false;
        else
        return true;
    }
    void Recver(Connection* con)
    {
        while(1)
        {
            char buffer[1024]={0};
            ssize_t n=recv(con->_sock,buffer,sizeof(buffer)-1,0);  //为什么-1呢?客户端最后一个是否是/n换行符因此不需要读取
            if(n>=0)
            {
                buffer[n]=0;
                con->inbuffer+=buffer;
            }
            else
            {
                if(errno==EAGAIN||errno==EWOULDBLOCK)//数据读取完了
                break;
                else if(errno=EINTR)    //链接失败，再次链接
                continue;
                else
                {
                    con->_except(con);   
                }
            }   
        }
    }
    void Sender(Connection* con)
    {
        while(1)
        {
            ssize_t n=send(con->_sock,con->outbuffer.c_str(),con->outbuffer.size(),0);
            if(n>0)
            {
                con->outbuffer.erase(0,n);
                if(con->outbuffer.empty())break;
            }
            else
            {
                if(errno==EAGAIN||errno==EWOULDBLOCK)break;
                else if(errno==EINTR)continue;
                else
                {
                    con->_except(con);
                    break;
                }
            }
        }
         //添加进来的客户端默认事件不包括写事件，因此需要手动添加
        if(con->outbuffer.empty())EnableWriteRead(con->_sock,true,false);
        else EnableWriteRead(con->_sock,true,true);
    }
     void Excepter(Connection* con)
    {
        //关闭套接字，删除对应哈希映射关系,从Epoll中删除
        int sock=con->_sock;
        _connections.erase(sock);
        _poll.DeleteEpoll(sock);
        close(sock);
    }
    bool EnableWriteRead(int sock,bool read,bool write)
    {
        if(write&&read)
        _poll.ModifyEpoll(sock,EPOLLIN |EPOLLOUT);       
        else if(!write&&read)
        _poll.ModifyEpoll(sock,EPOLLIN);       
        else if(!write&&!read)
        _poll.ModifyEpoll(sock,0);       
        else
        _poll.ModifyEpoll(sock,EPOLLOUT);       
    }
private:
    int _listensock;
    int _port;
    struct epoll_event* _revs;
    int _revs_num;          //存放就绪事件的队列的最大长度
    unordered_map<int,Connection*> _connections;
    Epoll _poll;
};